/**
*		@file ProcTable.h
*		@brief ProcTable class
*
*		@author Lan Ziquan
*
*		@date 1/25/2012
*/
#ifndef PROCTALBE_H
#define PROCTALBE_H

#include "TNode.h"
#include "GNode.h"
#include "Utility.h"
#include <vector>
#include <set>
#include <queue>
#include <list>
#include <string>
#include <sstream>
using namespace std;

typedef int		ProcIdx;
typedef string	ProcName;
typedef vector<bool>	ProcSet;

/**
*		@brief Structure to store data entry
*/
struct ProcEntry{
	// proc idx, starts from 1
	ProcIdx		proc_idx;
	// proc name
	ProcName	proc_name;
	// proc starting stmt num
	StmtNum		stmt_num_start;
	// proc ending stmt num
	StmtNum		stmt_num_end;
	// proc ast root node reference
	TNode*		p_tnode_AST_root;
	// proc cfg root node reference
	GNode*		p_gnode_CFG_root;
	// proc calling hierarchy, 0 is the proc 
	int			proc_hierarchy;
	// set of caller procs
	set<ProcIdx>		set_callers;
	// set of callee procs
	set<ProcIdx>		set_callees;
};

class ProcTable{
public:
	/**
	*		@brief This method will return the number of ProcEntries in ProcTable
	*/
	static int			GetSize() {return vp_proc_entries_.size();};

	/**
	*		@brief If proc_name already exists, this method will return the ProcIdx of the existence
	*		Otherwise, this method will insert a new ProcEntry and return its ProcIdx
	*/
	static ProcIdx		InsertProc(ProcName proc_name);
	
	/**
	*		If proc_callee_name does not already exist, this method will a new ProcEntry with proc_callee_name
	*		Anyway, this method will establish Calls(proc_caller_name, proc_callee_name) and return ProcIdx of proc_callee_name
	*/
	static ProcIdx		InsertCallee(ProcName proc_caller_name, ProcName proc_callee_name);

	/**
	*		This method will set stmt_num_start and stmt_num_end for proc_idx
	*/
	static void			SetStmtNumRange(ProcIdx proc_idx, StmtNum stmt_num_start, StmtNum stmt_num_end);

	/**
	*		This method will set TNode reference for proc_idx
	*/
	static void			SetProcASTRoot(ProcIdx proc_idx, TNode* p_tnode_root);
	
	/**
	*		This method will set GNode reference for proc_idx
	*/
	static void			SetProcCFGRoot(ProcIdx proc_idx, GNode* p_gnode_root);

	/**
	*		If proc_name exists, this method will return its ProcIdx
	*		Otherwise, it will return -1
	*/
	static ProcIdx		GetProcIdx(ProcName proc_name);

	/**
	*		This method will return the ProcName with proc_idx
	*/
	static ProcName		GetProcName(ProcIdx proc_idx); 
	
	/**
	*		This method will return the TNode reference with proc_idx
	*/
	static TNode*		GetProcASTRoot(ProcIdx proc_idx);
	
	/**
	*		This method will return the GNode reference with proc_idx
	*/
	static GNode*		GetProcCFGRoot(ProcIdx proc_idx);

	/**
	*		This method will return the starting StmtNum with proc_idx
	*/
	static StmtNum		GetStmtNumStart(ProcIdx proc_idx);

	/**
	*		This method will return the ending StmtNum with proc_idx
	*/
	static StmtNum		GetStmtNumEnd(ProcIdx proc_idx);

	/**
	*		This method will return a queue of procdures with none ascending proc_hierarchies
	*/
	static queue<ProcIdx>	GetProcSequence();

	/**
	*		This method will return a ProcSet of callers
	*/
	static ProcSet		GetProcCallers(ProcIdx proc_idx);

	/**
	*		This method will return a ProcSet of callees
	*/
	static ProcSet		GetProcCallees(ProcIdx proc_idx);

	static ProcIdx		GetUndefinedProcIdx();

	/**
	*		This method will return a string representation of ProcTable
	*/
	static string		ToString();

	static void			InitProcPathTable();

	static void			SetProcPath(ProcIdx proc_idx_previous, ProcIdx proc_idx_current);

	static bool			IsProcPath(ProcIdx proc_idx_1, ProcIdx proc_idx_2);

private:
	static vector<ProcEntry*>	vp_proc_entries_;
	static vector<ProcSet>		ProcPath_table_;

	/**
	*		If proc_name exists, this method will assign *pp_proc_entry to that reference and return true
	*		Otherwise, it will returns false
	*/
	static bool			CheckProcNameExistence(ProcName proc_name, ProcEntry** pp_proc_entry);

	/**
	*		This method will return a reference to the ProcEntry with proc_idx
	*/
	static ProcEntry*	GetProcEntry(ProcIdx proc_idx);
};


#endif